﻿using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Reflection;
using EasyComm.Contracts;
using EasyComm.ServiceUnit;
using EasyComm.Utilities;

namespace EasyComm.Hosting.Administration.Services
{
    public class WorkerAdminService : IAdminWorkerContract
    {
        private Type _serviceType;
        private WorkerServiceHost _workerHost;
        private Uri _nlbDiscoveryProxyAddress;
        private Uri _slbDiscoveryProxyAddress;
        private List<Type> _serviceContractList = new List<Type>();

        public ServiceResponse Initialize(Type serviceType, Uri NLBDiscoveryProxyAddress, Uri SLBDiscoveryProxyAddress)
        {
            try
            {
                _serviceType = serviceType;
                _nlbDiscoveryProxyAddress = NLBDiscoveryProxyAddress;
                _slbDiscoveryProxyAddress = SLBDiscoveryProxyAddress;
                string contractFolderPath = Path.Combine(Path.GetDirectoryName(Assembly.GetEntryAssembly().Location), "Contracts");
                if (!Directory.Exists(contractFolderPath))
                {
                    return new ServiceResponse(1, string.Format("No contracts found on '{0}'.", contractFolderPath), MessageType.Warn);
                }
                string[] contractAssemblyList = Directory.GetFiles(contractFolderPath, "*.dll");
                foreach (string filePath in contractAssemblyList)
                {
                    List<Type> contracts = ReflectionContext.FindContractInterfaces(filePath);
                    if (contracts.Count > 0)
                    {
                        _serviceContractList.AddRange(contracts);
                    }
                }
                if (_serviceContractList.Count > 0)
                {
                    return RestartServices();
                }
                else
                {
                    return new ServiceResponse(1, "Assembly does not implement any contracts.", MessageType.Warn);
                }
            }
            catch (Exception ex)
            {
                return new ServiceResponse(2, ex.ToString(), MessageType.Error);
            }
        }

        public WorkerServiceUnit GetWorkerService()
        {
            WorkerServiceUnit service = null;
            service.Status = ServiceStatus.NA;
            if (_workerHost != null)
            {
                service = new WorkerServiceUnit(_workerHost);
                if (_workerHost.State == System.ServiceModel.CommunicationState.Opened)
                {
                    service.Status = ServiceStatus.Online;
                }
                else
                {
                    service.Status = ServiceStatus.Offline;
                }
            }
            return service;
        }

        public ServiceResponse LoadWorkerServiceAssembly(byte[] file, string fileName)
        {
            try
            {
                string filePath = Path.Combine(Path.GetDirectoryName(Assembly.GetEntryAssembly().Location), "Contracts", fileName);
                FileUtils.SaveFile(file, filePath);
                List<Type> contracts = ReflectionContext.FindContractInterfaces(filePath);
                if (contracts.Count > 0)
                {
                    _serviceContractList.AddRange(contracts);
                }
                else
                {
                    return new ServiceResponse(1, "Assembly does not implement any contracts.", MessageType.Warn);
                }
                return RestartServices();
            }
            catch (Exception ex)
            {
                return new ServiceResponse(2, ex.ToString(), MessageType.Error);
            }
        }

        private ServiceResponse StopWorkerService()
        {
            try
            {
                if (_workerHost != null)
                {
                    _workerHost.Close();
                    _workerHost = null;
                }
                Trace.WriteLine("WorkerHost stopped.");
                Trace.WriteLine("");
                return new ServiceResponse();
            }
            catch (Exception ex)
            {
                return new ServiceResponse(2, ex.ToString(), MessageType.Error);
            }
        }

        private ServiceResponse SetWorkerService()
        {
            try
            {
                if (_workerHost == null)
                {
                    _workerHost = new WorkerServiceHost(_serviceType, _serviceContractList.ToArray(), new Uri[] { _slbDiscoveryProxyAddress, _nlbDiscoveryProxyAddress });
                    _workerHost.Open();
                }
                Trace.WriteLine(string.Format("WorkerHost listening on '{0}'...", _workerHost.Contracts[0].ListenUri));
                Trace.WriteLine("");

                return new ServiceResponse();
            }
            catch (Exception ex)
            {
                return new ServiceResponse(2, ex.ToString(), MessageType.Error);
            }
        }

        private ServiceResponse RestartServices()
        {
            ServiceResponse response = StopWorkerService();
            if (response.Code != 0)
            {
                return response;
            }
            return SetWorkerService();
        }
    }
}
